﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Runtime.Versioning;
using System.Windows.Forms;

namespace zykControl
{

    /// <summary>
    /// 用于代换 Microsoft Hierarchical FlexGrid Control 控件
    /// </summary>
    /// <remarks></remarks>
    [SupportedOSPlatform("windows")]
    public partial class ZykHFGrid
    {
        public ZykHFGrid()
        {
            mHead = new ZykHFGridColumns(this);
            mBody = new ZykHFGridRoot(this);
            InitializeComponent();
        }

        private readonly ZykHFGridColumns mHead;
        private readonly ZykHFGridRoot mBody;

        public ZykHFGridRoot Body
        {
            get
            {
                return mBody;
            }
        }

        [System.ComponentModel.Browsable(false)]
        public ZykHFGridColumns Columns
        {
            get
            {
                return mHead;
            }
        }

        /// <summary>
        /// 添加一个数据行,如果最后一个区的Key与theKey相同则在此区添加,否则在新区添加
        /// </summary>
        /// <param name="theKey">所添加的区的Key</param>
        /// <param name="theText">所有单元格的文本</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public ZykHFGridRow AddRow(string theKey, string[] theText)
        {
            return Body.AddRow(theKey, theText);
        }

        public ZykHFGridRow AddRow(string theKey)
        {
            return Body.AddRow(theKey);
        }

        /// <summary>
        /// 添加一个区,如果最后一个区的Key与theKey则返回找到的区,否则创建新区
        /// </summary>
        /// <param name="theKey"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public ZykHFGridArea AddRect(string theKey)
        {
            return Body.AddArea(theKey);
        }

        public int GetItemCount()
        {
            return Body.GetRowCount();
        }

        /// <summary>
        /// 清空表并重新填充
        /// </summary>
        /// <remarks></remarks>
        public void ColumnRefresh()
        {
            FlowLayoutPanel1.Controls.Clear();
            Columns.Refresh();
            for (int xx = 0; xx < Columns.Count; xx++)
                FlowLayoutPanel1.Controls.Add(Columns[xx]);
        }

        public void BodyRefresh()
        {
            Body.Refresh();
        }

        public void ColumnsClear()
        {
            Columns.Clear();
        }

        public void ColumnsAdd(string theTitle, int theWidth = 100)
        {
            Columns.Add(theTitle, theWidth);
        }

        //private void Body_CellSelectChanged(zykHFGridRow theCell)
        //{
        //    CellSelectChanged?.Invoke(theCell);
        //}

        ///// <summary>
        ///// 当选定的单元格发生改变时发生
        ///// </summary>
        ///// <remarks></remarks>
        //public event CellSelectChangedEventHandler CellSelectChanged;

        //public delegate void CellSelectChangedEventHandler(zykHFGridRow theCell);

        //private void Body_ItemSelectChanged(zykHFGridCell theItem)
        //{
        //    var dItem = theItem;
        //    if (dItem is null)
        //        return;
        //    ItemSelectChanged?.Invoke(theItem);
        //    Body.Refresh();
        //}

        ///// <summary>
        ///// 当选定的项发生改变时发生
        ///// </summary>
        ///// <remarks></remarks>
        //public event ItemSelectChangedEventHandler ItemSelectChanged;

        //public delegate void ItemSelectChangedEventHandler(zykHFGridCell theItem);

        public Color BackColorSelectedItem
        {
            get
            {
                return Body.SelectedCellBgColor;
            }

            set
            {
                Body.SelectedCellBgColor = value;
            }
        }

        public Color BackColorSelectedRow
        {
            get
            {
                return Body.SelectedRowBgColor;
            }

            set
            {
                Body.SelectedRowBgColor = value;
            }
        }

        public Color BackColorDouble
        {
            get
            {
                return Body.BackColorDouble;
            }

            set
            {
                Body.BackColorDouble = value;
            }
        }

        public Color BackColorSingle
        {
            get
            {
                return Body.BackColorSingle;
            }

            set
            {
                Body.BackColorSingle = value;
            }
        }

        public Color BorderColor
        {
            get
            {
                return Body.BorderColor;
            }

            set
            {
                Body.BorderColor = value;
            }
        }

        public Color BorderColorSelected
        {
            get
            {
                return Body.BorderColorSelected;
            }

            set
            {
                Body.BorderColorSelected = value;
            }
        }

        public Font FontGrid
        {
            get
            {
                return Body.Font;
            }

            set
            {
                Body.Font = value;
            }
        }

        public Font FontGridSelected
        {
            get
            {
                return Body.FontSelected;
            }

            set
            {
                Body.FontSelected = value;
            }
        }

        /// <summary>
        /// 返回/设置列标头部分的背景色
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [System.ComponentModel.Description("返回/设置列标头部分的背景色")]
        public Color HeadBackColor
        {
            get
            {
                return FlowLayoutPanel1.BackColor;
            }

            set
            {
                FlowLayoutPanel1.BackColor = value;
            }
        }

        /// <summary>
        /// 设置某列的前景色
        /// </summary>
        /// <param name="theIndex"></param>
        /// <param name="theColor"></param>
        /// <remarks></remarks>
        public void SetColumnForeColor(int theIndex, Color theColor)
        {
            if (theIndex < 0 || theIndex > Columns.Count - 1) return;
            Columns[theIndex].ForeColor = theColor;
        }

        /// <summary>
        /// 设置某列的背景色
        /// </summary>
        /// <param name="theIndex"></param>
        /// <param name="theColor"></param>
        /// <remarks></remarks>
        public void SetColumnBackColor(int theIndex, Color theColor)
        {
            if (theIndex < 0 || theIndex > Columns.Count - 1) return;
            Columns[theIndex].BackColor = theColor;
        }

        /// <summary>
        /// 向上移动选项
        /// </summary>
        /// <remarks></remarks>
        public void OnItemSelectUp()
        {
            Body.OnItemSelectUp();
        }

        /// <summary>
        /// 向下移动选项
        /// </summary>
        /// <remarks></remarks>
        public void OnItemSelectDown()
        {
            Body.OnItemSelectDown();
        }

        /// <summary>
        /// 向左移动选项
        /// </summary>
        /// <remarks></remarks>
        public void OnItemSelectLeft()
        {
            Body.OnItemSelectLeft();
        }

        /// <summary>
        /// 向右移动选项
        /// </summary>
        /// <remarks></remarks>
        public void OnItemSelectRight()
        {
            Body.OnItemSelectRight();
        }

        private ZykHFGridStyle? mDataStyle;

        /// <summary>
        /// 为setDataSource设置显示布局
        /// </summary>
        /// <param name="theStyle"></param>
        /// <remarks></remarks>
        [SupportedOSPlatform("windows")]
        public void SetDataStyle(ZykHFGridStyle theStyle)
        {
            mDataStyle = theStyle;
            Columns.Clear();
            for (int xx = 0; xx < theStyle.Count; xx++)
            {
                {
                    var withBlock = Columns.Add(theStyle[xx].Caption, theStyle[xx].Width);
                    withBlock.ItemAlign = theStyle[xx].Align;
                    withBlock.IsBill = theStyle[xx].IsBill;
                    withBlock.Visible = theStyle[xx].Visible;
                }
            }

            ColumnRefresh();
        }

        /// <summary>
        /// 使用数据源填充网格,必须在首次设置显示布局
        /// </summary>
        /// <param name="theTable">数据来源表</param>
        /// <remarks></remarks>
        public void SetDataSource(DataTable theTable)
        {
            Body.Clear();
            var theStyle = mDataStyle;
            if (theStyle is null) return;

            for (int xx = 0; xx < theStyle.Count; xx++)
            {
                if (theTable.Columns.IndexOf(theStyle[xx].DataColumnName) < 0) return;
            }

            if (theTable.Columns.IndexOf(theStyle.KeyRowName) < 0) return;

            var dKey = theTable.Columns[theStyle.KeyRowName];
            if (dKey == null) return;

            var dText = new string[theStyle.Count];
            for (int xx = 0, loopTo1 = theTable.Rows.Count - 1; xx <= loopTo1; xx++)
            {
                var dRow = theTable.Rows[xx];
                for (int yy = 0, loopTo2 = dText.Length - 1; yy <= loopTo2; yy++)
                    dText[xx] = "";
                string dKeyText = dRow[dKey]?.ToString() ?? "";
                for (int yy = 0, loopTo3 = theStyle.Count - 1; yy <= loopTo3; yy++)
                {
                    var dStyle = theStyle[yy];
                    if (dRow[dStyle.DataColumnName] != DBNull.Value) dText[yy] = dRow[dStyle.DataColumnName].ToString() ?? "";
                }

                AddRow(dKeyText, dText);
            }

            ColumnRefresh();
            BodyRefresh();
        }

        public void Clear()
        {
            Columns.Clear();
            Body.Clear();
        }

        /// <summary>
        /// 返回区块的总数
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [System.ComponentModel.Browsable(false)]
        public int RowCount
        {
            get
            {
                return Body.Count;
            }
        }

        [System.ComponentModel.Browsable(false)]
        public ZykHFGridArea this[int Index]
        {
            get
            {
                return Body[Index];
            }
        }

        /// <summary>
        /// 清空所有区块
        /// </summary>
        /// <remarks></remarks>
        public void RowClear()
        {
            Body.Clear();
        }

        [System.ComponentModel.Browsable(false)]
        public ZykHFGridCell? SelectedCell
        {
            get
            {
                return Body.SelectedCell;
            }

            set
            {
                Body.SelectedCell = value;
            }
        }

        [System.ComponentModel.Browsable(false)]
        public ZykHFGridArea? SelectedArea
        {
            get
            {
                return Body.SelectedArea;
            }

            set
            {
                Body.SelectedArea = value;
            }
        }

        [System.ComponentModel.Browsable(false)]
        public ZykHFGridRow? SelectedRow
        {
            get
            {
                return Body.SelectedRow;
            }

            set
            {
                Body.SelectedRow = value;
            }
        }

        [System.ComponentModel.Browsable(false)]
        public int SelectedAreaIndex
        {
            get
            {
                return Body.SelectedAreaIndex;
            }

            set
            {
                Body.SelectedAreaIndex = value;
            }
        }

        private void GridBody_Click(object sender, EventArgs e)
        {
            OnClick(e);
        }

        private void Panel1_MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta > 0)
            {
                if (VScrollBar1.Value <= VScrollBar1.Minimum)
                {
                    return;
                }
                else
                {
                    int dValue = VScrollBar1.Value - 3;
                    if (dValue < VScrollBar1.Minimum)
                        dValue = VScrollBar1.Minimum;
                    VScrollBar1.Value = dValue;
                }
            }
            else if (e.Delta < 0)
            {
                if (VScrollBar1.Value >= VScrollBar1.Maximum)
                {
                    return;
                }
                else
                {
                    int dValue = VScrollBar1.Value + 3;
                    if (dValue > VScrollBar1.Maximum)
                        dValue = VScrollBar1.Maximum;
                    VScrollBar1.Value = dValue;
                }
            }
        }

        private void Panel1_Paint(object sender, PaintEventArgs e)
        {
            Body.OnPaint(e);
        }

        private void Panel1_MouseDown(object sender, MouseEventArgs e)
        {
            GridBody.Focus();
            var dCell = Body.GetCellByPoint(e.Location);
            dCell?.ToSelected();
            OnMouseDown(e);
        }

        private void Panel1_SizeChanged(object sender, EventArgs e)
        {
            Body.Refresh();
        }

        private void VScrollBar1_Enter(object sender, EventArgs e)
        {
            Focus();
        }

        /// <summary>
        /// 垂直滚动条
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks></remarks>
        private void VScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            Body.Refresh();
        }

        /// <summary>
        /// 水平滚动务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks></remarks>
        private void HScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            FlowLayoutPanel1.Left = -Body.XOffset;
            Body.Refresh();
        }

        //private void mHead_ColumnCountChanged()
        //{
        //    Body.OnColumnCountChanged();
        //}

        private void ZykHFGrid_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Up:
                    {
                        OnItemSelectUp();
                        break;
                    }

                case Keys.Down:
                    {
                        OnItemSelectDown();
                        break;
                    }

                case Keys.Left:
                    {
                        OnItemSelectLeft();
                        break;
                    }

                case Keys.Right:
                    {
                        OnItemSelectRight();
                        break;
                    }
            }
        }

        private void HScrollBar1_Enter(object sender, EventArgs e)
        {
            Focus();
        }

        private void GridBody_DoubleClick(object sender, EventArgs e)
        {
            OnDoubleClick(e);
        }

        private void GridBody_MouseClick(object sender, MouseEventArgs e)
        {
            OnMouseClick(e);
        }

        private void GridBody_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            OnMouseDoubleClick(e);
        }

        /// <summary>
        /// 返回/设置垂直滚动条的位置
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public int VPosition
        {
            get
            {
                return VScrollBar1.Value;
            }

            set
            {
                if (value > VScrollBar1.Maximum)
                    value = VScrollBar1.Maximum;
                if (value < VScrollBar1.Minimum)
                    value = VScrollBar1.Value;
                VScrollBar1.Value = value;
            }
        }

        /// <summary>
        /// 确保某区块的某行处于可见位置
        /// </summary>
        /// <param name="theAreaIndex"></param>
        /// <param name="theRowIndex"></param>
        /// <remarks></remarks>
        public void EnsureVisible(int theAreaIndex, int theRowIndex)
        {
            var dArea = Body[theAreaIndex];
            var dRow = dArea[theRowIndex];
            int dCount = dRow.GetBodyRowIndex();
            int dShowRows = ShowRowCount();
            if (dCount < 0)
                return;

            // 当待显数据隐于下面时
            if (dCount - VScrollBar1.Value > dShowRows)
            {
                VScrollBar1.Value = dCount - dShowRows + 1 - VScrollBar1.Minimum;
            }
            // 当待显数据隐于上面时
            if (dCount - VScrollBar1.Value < 0)
            {
                VScrollBar1.Value = dCount;
            }
        }

        /// <summary>
        /// 返回数据网格可显示的行数,半行不算一行
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public int ShowRowCount()
        {
            int dCount = VScrollBar1.Height / Body.ItemHeidht;
            return dCount;
        }

        /// <summary>
        /// 确保某区块的第一行处于可见位置
        /// </summary>
        /// <param name="theAreaIndex"></param>
        /// <remarks></remarks>
        public void EnsureVisible(int theAreaIndex)
        {
            EnsureVisible(theAreaIndex, 0);
        }

        /// <summary>
        /// 确保被选中区块的被选中行处于可见位置
        /// </summary>
        /// <remarks></remarks>
        public void EnsureVisible()
        {
            if (SelectedRow is null) return;
            EnsureVisible(SelectedRow.Area.Index, SelectedRow.Index);
        }
    }

    /// <summary>
    /// 用于对zykHFGrid控件的数据源的布局定义
    /// </summary>
    /// <remarks></remarks>
    /// <remarks>
    /// 对象实例化
    /// </remarks>
    /// <param name="theKeyRowName">在DataTable中的数据列,此列的内容做为zykHFGrid控件中行的标志</param>
    /// <remarks></remarks>
    [SupportedOSPlatform("windows")]
    public class ZykHFGridStyle(string theKeyRowName)
    {
        private readonly List<ZykHFGridStyleColumn> mItems = [];
        public readonly string KeyRowName = theKeyRowName;

        public int Count
        {
            get
            {
                return mItems.Count;
            }
        }

        public ZykHFGridStyleColumn this[int Index]
        {
            get
            {
                return mItems[Index];
            }
        }

        public ZykHFGridStyleColumn Add(ZykHFGridStyleColumn theItem)
        {
            mItems.Add(theItem);
            return theItem;
        }

        /// <summary>
        /// 添加一个布局项
        /// </summary>
        /// <param name="theDataColumnName">DataTable中的列名</param>
        /// <param name="theCaption">显示在网格头部的文本</param>
        /// <param name="theIsBill">此列是否为单据行</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public ZykHFGridStyleColumn Add(string theDataColumnName, string theCaption, bool theIsBill = false)
        {
            var dItem = new ZykHFGridStyleColumn(theDataColumnName, theCaption, theIsBill);
            mItems.Add(dItem);
            return dItem;
        }
    }

    /// <summary>
    /// 布局定义的项
    /// </summary>
    /// <remarks></remarks>
    [SupportedOSPlatform("windows")]
    public class ZykHFGridStyleColumn(string theDataColumnName, string theCaption, bool theIsBill)
    {
        public readonly string DataColumnName = theDataColumnName;
        public readonly string Caption = theCaption;
        public readonly bool IsBill = theIsBill;
        public int Width = 100;
        public ContentAlignment Align = ContentAlignment.MiddleLeft;
        public readonly ContentAlignment ItemFormat = ContentAlignment.MiddleLeft;
        public bool Visible = true;
        public string FormatString = "";
    }
}